package net.luerything.restlet.gwt.rpc;

import com.google.gwt.user.server.rpc.SerializationPolicy;
import com.google.gwt.user.server.rpc.SerializationPolicyProvider;
import org.restlet.Context;
import org.restlet.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.ParseException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author keke
 * @see net.luerything.restlet.gwt.rpc.PolicyLoader
 * @see net.luerything.restlet.gwt.rpc.PolicyFileResolver
 */
public class DefaultSerializationPolicyProvider implements SerializationPolicyProvider {
  private static final Logger LOG = LoggerFactory.getLogger(DefaultSerializationPolicyProvider.class);

  private final ConcurrentMap<String, SerializationPolicy> policyCache;
  private PolicyFileResolver resolver;
  private PolicyLoader loader;

  /**
   * @param resolver
   * @param loader
   */
  public DefaultSerializationPolicyProvider(final PolicyFileResolver resolver, final PolicyLoader loader) {
    assert resolver != null;
    assert loader != null;
    this.resolver = resolver;
    this.loader = loader;
    policyCache = new ConcurrentHashMap<String, SerializationPolicy>();
  }

  public SerializationPolicy getSerializationPolicy(final String moduleBaseName,
                                                    final String strongName) {
    assert moduleBaseName != null && strongName != null;
    final String key = moduleBaseName + strongName;
    SerializationPolicy result = policyCache.get(key);
    if (result == null) {
      try {
        final String policyFileUrl = resolver.getPolicyFileURI(moduleBaseName, strongName);
        if (policyFileUrl != null) {
          final Response response = Context.getCurrent().getClientDispatcher().get(policyFileUrl);
          assert response != null;
          if (response.getStatus().isSuccess()) {
            result = loader.loadFromStream(response.getEntity().getStream(), null);
            policyCache.putIfAbsent(key, result);
          } else {
            LOG.error("Unable to find policy file by {}", policyFileUrl);
          }
        } else {
          LOG.error("Unable to resolve policy file URL");
        }
      } catch (IOException e) {
        LOG.error("Unable to load policy file ", e);
      } catch (ParseException e) {
        LOG.error("Unable to load policy file ", e);
      }
    }
    return result;
  }
}